package com.sqtracker.recommender.strategy;

import com.sqtracker.recommender.dto.RecommendationRequest;
import com.sqtracker.recommender.dto.RecommendationResponse;
import com.sqtracker.recommender.model.TorrentMetadataExt;
import com.sqtracker.recommender.model.UserBehavior;
import com.sqtracker.recommender.model.UserPreference;
import com.sqtracker.recommender.repository.TorrentMetadataExtRepository;
import com.sqtracker.recommender.repository.UserBehaviorRepository;
import com.sqtracker.recommender.repository.UserPreferenceRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 冷启动策略 - 处理新用户的推荐
 */
@Component
public class ColdStartStrategy {

    private final TorrentMetadataExtRepository torrentMetadataExtRepository;
    private final UserBehaviorRepository userBehaviorRepository;
    private final UserPreferenceRepository userPreferenceRepository;

    @Value("${recommendation.cold-start.default-recommendations:20}")
    private int defaultRecommendationCount;

    private Random random = new Random();

    @Autowired
    public ColdStartStrategy(
            TorrentMetadataExtRepository torrentMetadataExtRepository,
            UserBehaviorRepository userBehaviorRepository,
            UserPreferenceRepository userPreferenceRepository) {
        this.torrentMetadataExtRepository = torrentMetadataExtRepository;
        this.userBehaviorRepository = userBehaviorRepository;
        this.userPreferenceRepository = userPreferenceRepository;
    }

    /**
     * 为新用户生成推荐
     */
    public RecommendationResponse getRecommendations(RecommendationRequest request) {
        String userId = request.getUserId();
        int count = request.getCount();

        // 1. 检查用户是否有显式偏好设置
        Optional<UserPreference> userPrefOpt = userPreferenceRepository.findByUserId(userId);

        if (userPrefOpt.isPresent() && hasExplicitPreferences(userPrefOpt.get())) {
            // 如果有显式偏好，基于偏好推荐
            return getRecommendationsByPreference(userPrefOpt.get(), count);
        }

        // 2. 检查用户是否有少量的行为记录
        List<UserBehavior> behaviors = userBehaviorRepository.findByUserId(userId);

        if (!behaviors.isEmpty()) {
            // 如果有少量行为，基于行为推荐
            return getRecommendationsByLimitedBehavior(behaviors, count);
        }

        // 3. 如果没有任何信息，返回热门+多样性推荐
        return getDefaultRecommendations(count);
    }

    /**
     * 检查用户是否有显式偏好设置
     */
    private boolean hasExplicitPreferences(UserPreference preference) {
        UserPreference.ExplicitPreferences explicitPrefs = preference.getExplicitPreferences();

        if (explicitPrefs == null) {
            return false;
        }

        boolean hasCategories = explicitPrefs.getCategories() != null && !explicitPrefs.getCategories().isEmpty();
        boolean hasTags = explicitPrefs.getTags() != null && !explicitPrefs.getTags().isEmpty();
        boolean hasLanguages = explicitPrefs.getLanguages() != null && !explicitPrefs.getLanguages().isEmpty();

        return hasCategories || hasTags || hasLanguages;
    }

    /**
     * 基于用户偏好设置生成推荐
     */
    private RecommendationResponse getRecommendationsByPreference(UserPreference preference, int count) {
        UserPreference.ExplicitPreferences explicitPrefs = preference.getExplicitPreferences();

        // 获取可能的匹配资源
        List<TorrentMetadataExt> candidates = new ArrayList<>();

        // 根据分类筛选
        if (explicitPrefs.getCategories() != null && !explicitPrefs.getCategories().isEmpty()) {
            for (String categoryId : explicitPrefs.getCategories()) {
                candidates.addAll(torrentMetadataExtRepository.findByTorrentCategoryId(categoryId));
            }
        }

        // 如果没有足够的候选项，添加一些热门资源
        if (candidates.size() < count * 2) {
            candidates.addAll(torrentMetadataExtRepository.findAll(
                    Sort.by(Sort.Direction.DESC, "popularity")
            ));
        }

        // 对候选资源进行评分
        Map<String, Double> scoreMap = new HashMap<>();

        for (TorrentMetadataExt torrent : candidates) {
            double score = 0.0;

            // 根据分类匹配加分
            if (explicitPrefs.getCategories() != null && torrent.getTorrentCategoryId() != null) {
                if (explicitPrefs.getCategories().contains(torrent.getTorrentCategoryId())) {
                    score += 0.5;
                }
            }

            // 根据标签匹配加分
            if (explicitPrefs.getTags() != null && torrent.getTags() != null) {
                for (String tag : torrent.getTags()) {
                    if (explicitPrefs.getTags().contains(tag)) {
                        score += 0.3;
                    }
                }
            }

            // 根据语言匹配加分
            if (explicitPrefs.getLanguages() != null && torrent.getLanguage() != null) {
                if (explicitPrefs.getLanguages().contains(torrent.getLanguage())) {
                    score += 0.2;
                }
            }

            // 根据流行度加分
            if (torrent.getPopularity() != null) {
                score += torrent.getPopularity() * 0.2;
            }

            // 根据新鲜度加分
            if (torrent.getFreshness() != null) {
                score += torrent.getFreshness() * 0.1;
            }

            scoreMap.put(torrent.getTorrentId(), score);
        }

        // 排序并截取前N个推荐
        List<Map.Entry<String, Double>> sortedItems = scoreMap.entrySet().stream()
                .sorted(Map.Entry.<String, Double>comparingByValue().reversed())
                .limit(count)
                .collect(Collectors.toList());

        // 构建推荐响应
        RecommendationResponse response = new RecommendationResponse();
        response.setRecommendations(buildRecommendationItems(sortedItems, "cold-start-preference"));

        return response;
    }

    /**
     * 基于有限的用户行为生成推荐
     */
    private RecommendationResponse getRecommendationsByLimitedBehavior(List<UserBehavior> behaviors, int count) {
        // 获取用户交互的种子ID
        Set<String> interactedTorrentIds = behaviors.stream()
                .map(UserBehavior::getTorrentId)
                .collect(Collectors.toSet());

        // 获取用户交互的种子元数据
        List<TorrentMetadataExt> interactedTorrents = interactedTorrentIds.stream()
                .map(id -> torrentMetadataExtRepository.findByTorrentId(id))
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(Collectors.toList());

        // 提取用户可能感兴趣的特征
        Set<String> categories = new HashSet<>();
        Set<String> tags = new HashSet<>();
        Set<String> languages = new HashSet<>();

        for (TorrentMetadataExt torrent : interactedTorrents) {
            if (torrent.getTorrentCategoryId() != null) {
                categories.add(torrent.getTorrentCategoryId());
            }

            if (torrent.getTags() != null) {
                tags.addAll(torrent.getTags());
            }

            if (torrent.getLanguage() != null) {
                languages.add(torrent.getLanguage());
            }
        }

        // 获取可能的匹配资源
        List<TorrentMetadataExt> candidates = torrentMetadataExtRepository.findAll(
                Sort.by(Sort.Direction.DESC, "popularity")
        );

        // 排除已交互的资源
        candidates = candidates.stream()
                .filter(t -> !interactedTorrentIds.contains(t.getTorrentId()))
                .collect(Collectors.toList());

        // 对候选资源进行评分
        Map<String, Double> scoreMap = new HashMap<>();

        for (TorrentMetadataExt torrent : candidates) {
            double score = 0.0;

            // 根据分类匹配加分
            if (torrent.getTorrentCategoryId() != null && categories.contains(torrent.getTorrentCategoryId())) {
                score += 0.5;
            }

            // 根据标签匹配加分
            if (torrent.getTags() != null) {
                for (String tag : torrent.getTags()) {
                    if (tags.contains(tag)) {
                        score += 0.3;
                    }
                }
            }

            // 根据语言匹配加分
            if (torrent.getLanguage() != null && languages.contains(torrent.getLanguage())) {
                score += 0.2;
            }

            // 根据流行度加分
            if (torrent.getPopularity() != null) {
                score += torrent.getPopularity() * 0.2;
            }

            scoreMap.put(torrent.getTorrentId(), score);
        }

        // 排序并截取前N个推荐
        List<Map.Entry<String, Double>> sortedItems = scoreMap.entrySet().stream()
                .sorted(Map.Entry.<String, Double>comparingByValue().reversed())
                .limit(count)
                .collect(Collectors.toList());

        // 构建推荐响应
        RecommendationResponse response = new RecommendationResponse();
        response.setRecommendations(buildRecommendationItems(sortedItems, "cold-start-behavior"));

        return response;
    }

    /**
     * 生成默认推荐
     */
    private RecommendationResponse getDefaultRecommendations(int count) {
        // 获取热门资源
        List<TorrentMetadataExt> popularTorrents = torrentMetadataExtRepository.findAll(
                Sort.by(Sort.Direction.DESC, "popularity", "lastUpdated")
        ).stream().limit(defaultRecommendationCount).collect(Collectors.toList());

        // 随机选择一部分
        List<TorrentMetadataExt> selectedTorrents = getRandomSubset(popularTorrents, count);

        // 构建推荐响应
        List<Map<String, Object>> recommendations = new ArrayList<>();

        for (TorrentMetadataExt torrent : selectedTorrents) {
            Map<String, Object> item = new HashMap<>();
            item.put("torrentId", torrent.getTorrentId());
            item.put("score", torrent.getPopularity() != null ? torrent.getPopularity() : 0.5);
            item.put("algorithm", "cold-start-default");
            item.put("reason", "热门推荐");

            recommendations.add(item);
        }

        RecommendationResponse response = new RecommendationResponse();
        response.setRecommendations(recommendations);

        return response;
    }

    /**
     * 构建推荐项目
     */
    private List<Map<String, Object>> buildRecommendationItems(List<Map.Entry<String, Double>> sortedItems, String algorithm) {
        List<Map<String, Object>> recommendations = new ArrayList<>();

        for (Map.Entry<String, Double> entry : sortedItems) {
            String torrentId = entry.getKey();
            double score = entry.getValue();

            Map<String, Object> item = new HashMap<>();
            item.put("torrentId", torrentId);
            item.put("score", score);
            item.put("algorithm", algorithm);
            item.put("reason", "根据您的兴趣推荐");

            recommendations.add(item);
        }

        return recommendations;
    }

    /**
     * 从集合中随机选择子集
     */
    private <T> List<T> getRandomSubset(List<T> list, int size) {
        if (list.size() <= size) {
            return new ArrayList<>(list);
        }

        List<T> result = new ArrayList<>(size);
        Set<Integer> selectedIndices = new HashSet<>();

        while (result.size() < size) {
            int index = random.nextInt(list.size());

            if (!selectedIndices.contains(index)) {
                selectedIndices.add(index);
                result.add(list.get(index));
            }
        }

        return result;
    }
}